package com.foo.classifiers;

import java.util.Random;

import weka.classifiers.Classifier;
import weka.classifiers.Evaluation;
import weka.classifiers.bayes.NaiveBayes;
import weka.core.Instances;
import weka.filters.unsupervised.attribute.StringToWordVector;

import com.foo.constants.Constants;
import com.foo.preprocessing.CreatingArffFile;
import com.foo.preprocessing.PreprocessedDataset;

public class NaiveBayesianOptions {

	public Evaluation buildNaiveBayesClassifier(Instances rawData, int noOfFolds, int noOfSeeds) {
		
		Evaluation evaluation = null;
		Instances filteredData;
		try
		{
			//Step 2: Apply Filters
			//Apply StringtoNominal filter for the category attribute
			PreprocessedDataset preprocessedObj = new PreprocessedDataset();
			filteredData = preprocessedObj.Apply_String_To_Nominal_Filters(rawData);
			
			//Apply StringtoWordVector filter for the remaining attribute
			filteredData = preprocessedObj.Apply_String_To_Vector_Filters(filteredData);
			
			//Step 3: Build Classifier
			NaiveBayes classifier = new NaiveBayes();
			classifier.setUseKernelEstimator(true);
			classifier.setUseSupervisedDiscretization(true);
		    Classifier naivebayes = (Classifier) classifier;
		    naivebayes.buildClassifier(filteredData);
			
		    //Step 4: Validate Classifier using cross validation technique
		    evaluation = new Evaluation(filteredData);
		    evaluation.crossValidateModel(naivebayes, filteredData, noOfFolds, new Random(noOfSeeds));
		}
		catch(Exception e)
		{
			System.err.println("Error Building classifier");
		}
		return evaluation;
	}
	
	
	/*
	 * Creating a Naive Bayesian Classifier with all feature selection
	 */
	public Evaluation createInstanceAllFeatures(int noOfFolds, int noOfSeeds)
	{
		Instances rawData =null;
		Evaluation evaluation = null;
		try
		{			
			//Step1: Creating Weka specific Arff file
			CreatingArffFile createObj = new CreatingArffFile();
			rawData = createObj.create_ArffFile();
			
			evaluation = buildNaiveBayesClassifier(rawData, noOfFolds, noOfSeeds);
		}
		catch(Exception e)
		{
			System.err.println("Error Creating Arff file :" + e.getMessage());
		}
		return evaluation;
	}
	

	/*
	 * Creating a Naive Bayesian Classifier with only Source feature selection
	 */
	public Evaluation createInstanceSource(int noOfFolds, int noOfSeeds)
	{
		Instances rawData =null;
		Evaluation evaluation = null;
		try
		{			
			//Step1: Creating Weka specific Arff file
			CreatingArffFile createObj = new CreatingArffFile();
			rawData = createObj.create_ArffFile(Constants.SOURCE_ATTRIBUTE);
			
			evaluation = buildNaiveBayesClassifier(rawData, noOfFolds, noOfSeeds);
		}
		catch(Exception e)
		{
			System.err.println("Error Creating Arff file :" + e.getMessage());
		}
		return evaluation;
	}

	/*
	 * Creating a Naive Bayesian with only Title feature selection
	 */
	public Evaluation createInstanceTitle(int noOfFolds, int noOfSeeds)
	{
		Instances rawData =null;
		Evaluation evaluation = null;
		try
		{			
			//Step1: Creating Weka specific Arff file
			CreatingArffFile createObj = new CreatingArffFile();
			rawData = createObj.create_ArffFile(Constants.TITLE_ATTRIBUTE);
			
			evaluation = buildNaiveBayesClassifier(rawData, noOfFolds, noOfSeeds);
		}
		catch(Exception e)
		{
			System.err.println("Error Creating Arff file :" + e.getMessage());
		}
		return evaluation;
	}

	/*
	 * Creating a Naive Bayesian with only Description feature selection
	 */
	public Evaluation createInstanceDesc(int noOfFolds, int noOfSeeds)
	{
		Instances rawData =null;
		Evaluation evaluation = null;
		try
		{			
			//Step1: Creating Weka specific Arff file
			CreatingArffFile createObj = new CreatingArffFile();
			rawData = createObj.create_ArffFile(Constants.DESCRIPTION_ATTRIBUTE);
			
			evaluation = buildNaiveBayesClassifier(rawData, noOfFolds, noOfSeeds);
		}
		catch(Exception e)
		{
			System.err.println("Error Creating Arff file :" + e.getMessage());
		}
		return evaluation;
	}

	/*
	 * Creating a Naive Bayesian Classifier with Source and Title feature selection
	 */
	public Evaluation createInstanceSourceTitle(int noOfFolds, int noOfSeeds)
	{
		Instances rawData =null;
		Evaluation evaluation = null;
		try
		{			
			//Step1: Creating Weka specific Arff file
			CreatingArffFile createObj = new CreatingArffFile();
			rawData = createObj.create_ArffFile(Constants.SOURCE_ATTRIBUTE,Constants.TITLE_ATTRIBUTE);
			
			evaluation = buildNaiveBayesClassifier(rawData, noOfFolds, noOfSeeds);
		}
		catch(Exception e)
		{
			System.err.println("Error Creating Arff file :" + e.getMessage());
		}
		return evaluation;
	}

	/*
	 * Creating a Naive Bayesian Classifier with Source and Description feature selection
	 */
	public Evaluation createInstanceSourceDescription(int noOfFolds, int noOfSeeds)
	{
		Instances rawData =null;
		Evaluation evaluation = null;
		try
		{			
			//Step1: Creating Weka specific Arff file
			CreatingArffFile createObj = new CreatingArffFile();
			rawData = createObj.create_ArffFile(Constants.SOURCE_ATTRIBUTE,Constants.DESCRIPTION_ATTRIBUTE);
			
			evaluation= buildNaiveBayesClassifier(rawData, noOfFolds, noOfSeeds);
		}
		catch(Exception e)
		{
			System.err.println("Error Creating Arff file :" + e.getMessage());
		}
		return evaluation;
	}

	/*
	 * Creating a Naive Bayesian with Title and Description feature selection
	 */
	public Evaluation createInstanceTitleDescription(int noOfFolds, int noOfSeeds)
	{
		Instances rawData =null;
		Evaluation evaluation = null;
		try
		{			
			//Step1: Creating Weka specific Arff file
			CreatingArffFile createObj = new CreatingArffFile();
			rawData = createObj.create_ArffFile(Constants.TITLE_ATTRIBUTE,Constants.DESCRIPTION_ATTRIBUTE);
			
			evaluation = buildNaiveBayesClassifier(rawData, noOfFolds, noOfSeeds);
		}
		catch(Exception e)
		{
			System.err.println("Error Creating Arff file :" + e.getMessage());
		}
		return evaluation;
	}

	/*
	 * Main Function to test the Naive Bayesian classifier with different feature selection 
	 * and different parameter setting
	 */
	
	public static void main(String args[]) throws Exception {
		
        NaiveBayesianOptions nb = new NaiveBayesianOptions();
		
		int noOfFolds = 10;
		int noOfSeeds = 1;
		
		Evaluation evaluation = null;
		StringBuilder output = null;
		
		//Case 1: Building the classifier with all instances and validating
		evaluation =  nb.createInstanceAllFeatures(noOfFolds, noOfSeeds);
		output = new StringBuilder();
		output.append("\n*******************************************************************\n");
		output.append(
			"Case 1: Building the Naive Bayesian classifier with options for all instances Output:");
		output.append("\nTotal Instance: " + evaluation.numInstances());
		output.append("\nPercentage of Correctly Classified Instance: " + evaluation.pctCorrect()+"%");
		output.append("\nPercentage of InCorrectly Classified Instance: " + evaluation.pctIncorrect() +"%");
		output.append("\nPercentage of UnClassified Instances: " + evaluation.pctUnclassified() +"%");
		output.append("\nAccuracy of Classifier: " + (evaluation.correct() / evaluation.numInstances()));
		output.append("\nError Rate of Classifier: " + evaluation.errorRate());
		output.append("\nConfusion Matrix of the Classifier: \n" + evaluation.toMatrixString("Case 1"));
		output.append("\nWeighted Precision of Classifier: " + evaluation.weightedPrecision());
		output.append("\nWeighted Recall of Classifier: " + evaluation.weightedRecall());
		output.append("\n*******************************************************************\n");
		
		
		System.out.println(output.toString());
		
		//Case 2: Building the classifier with only Source feature
		evaluation = nb.createInstanceSource(noOfFolds, noOfSeeds);
		
		output = new StringBuilder();
		output.append("\n*******************************************************************\n");
		output.append(
			"Case 2: Building the Naive Bayesian Classifier with options for only Source feature Output:");
		output.append("\nTotal Instance: " + evaluation.numInstances());
		output.append("\nPercentage of Correctly Classified Instance: " + evaluation.pctCorrect()+"%");
		output.append("\nPercentage of InCorrectly Classified Instance: " + evaluation.pctIncorrect() +"%");
		output.append("\nPercentage of UnClassified Instances: " + evaluation.pctUnclassified() +"%");
		output.append("\nAccuracy of Classifier: " + (evaluation.correct() / evaluation.numInstances()));
		output.append("\nError Rate of Classifier: " + evaluation.errorRate());
		output.append("\nConfusion Matrix of the Classifier: \n" + evaluation.toMatrixString("Case 2"));
		output.append("\nWeighted Precision of Classifier: " + evaluation.weightedPrecision());
		output.append("\nWeighted Recall of Classifier: " + evaluation.weightedRecall());
		output.append("\n*******************************************************************\n");
		
		System.out.println(output.toString());
		
		//Case 3: Building the classifier with only Title feature
		evaluation = nb.createInstanceTitle(noOfFolds, noOfSeeds);
		
		output = new StringBuilder();
		output.append("\n*******************************************************************\n");
		output.append(
				"Case 3: Building the Naive Bayesian Classifier with  options for only Title feature Output:");
		output.append("\nTotal Instance: " + evaluation.numInstances());
		output.append("\nPercentage of Correctly Classified Instance: " + evaluation.pctCorrect()+"%");
		output.append("\nPercentage of InCorrectly Classified Instance: " + evaluation.pctIncorrect() +"%");
		output.append("\nPercentage of UnClassified Instances: " + evaluation.pctUnclassified() +"%");
		output.append("\nAccuracy of Classifier: " + (evaluation.correct() / evaluation.numInstances()));
		output.append("\nError Rate of Classifier: " + evaluation.errorRate());
		output.append("\nConfusion Matrix of the Classifier: \n" + evaluation.toMatrixString("Case 3"));
		output.append("\nWeighted Precision of Classifier: " + evaluation.weightedPrecision());
		output.append("\nWeighted Recall of Classifier: " + evaluation.weightedRecall());
		output.append("\n*******************************************************************\n");
		
		System.out.println(output.toString());
		
		//Case 4: Building the classifier with only Description feature
		evaluation = nb.createInstanceDesc(noOfFolds, noOfSeeds);
		
		output = new StringBuilder();
		output.append("\n*******************************************************************\n");
		output.append(
				"Case 4: Building the Naive Bayesian Classifier with options for only Description feature Output:");
		output.append("\nTotal Instance: " + evaluation.numInstances());
		output.append("\nPercentage of Correctly Classified Instance: " + evaluation.pctCorrect()+"%");
		output.append("\nPercentage of InCorrectly Classified Instance: " + evaluation.pctIncorrect() +"%");
		output.append("\nPercentage of UnClassified Instances: " + evaluation.pctUnclassified() +"%");
		output.append("\nAccuracy of Classifier: " + (evaluation.correct() / evaluation.numInstances()));
		output.append("\nError Rate of Classifier: " + evaluation.errorRate());
		output.append("\nConfusion Matrix of the Classifier: \n" + evaluation.toMatrixString("Case 4"));
		output.append("\nWeighted Precision of Classifier: " + evaluation.weightedPrecision());
		output.append("\nWeighted Recall of Classifier: " + evaluation.weightedRecall());
		output.append("\n*******************************************************************\n");
		System.out.println(output.toString());
		
		//Case 5: Building the classifier with only Source and Title feature
		evaluation = nb.createInstanceSourceTitle(noOfFolds, noOfSeeds);
		
		output = new StringBuilder();
		output.append("\n*******************************************************************\n");
		output.append(
			"Case 5: Building the Naive Bayesian Classifier with options for only Source and Title feature Output:");
		output.append("\nTotal Instance: " + evaluation.numInstances());
		output.append("\nPercentage of Correctly Classified Instance: " + evaluation.pctCorrect()+"%");
		output.append("\nPercentage of InCorrectly Classified Instance: " + evaluation.pctIncorrect() +"%");
		output.append("\nPercentage of UnClassified Instances: " + evaluation.pctUnclassified() +"%");
		output.append("\nAccuracy of Classifier: " + (evaluation.correct() / evaluation.numInstances()));
		output.append("\nError Rate of Classifier: " + evaluation.errorRate());
		output.append("\nConfusion Matrix of the Classifier: \n" + evaluation.toMatrixString("Case 5"));
		output.append("\nWeighted Precision of Classifier: " + evaluation.weightedPrecision());
		output.append("\nWeighted Recall of Classifier: " + evaluation.weightedRecall());
		output.append("\n*******************************************************************\n");
		System.out.println(output.toString());
		
		//Case 6: Building the classifier with only Source and Description feature
		evaluation = nb.createInstanceSourceDescription(noOfFolds, noOfSeeds);
		
		output = new StringBuilder();
		output.append("\n*******************************************************************\n");
		output.append(
			"Case 6: Building the Naive Bayesian Classifier with  options for only Source and Description feature Output:");
		output.append("\nTotal Instance: " + evaluation.numInstances());
		output.append("\nPercentage of Correctly Classified Instance: " + evaluation.pctCorrect()+"%");
		output.append("\nPercentage of InCorrectly Classified Instance: " + evaluation.pctIncorrect() +"%");
		output.append("\nPercentage of UnClassified Instances: " + evaluation.pctUnclassified() +"%");
		output.append("\nAccuracy of Classifier: " + (evaluation.correct() / evaluation.numInstances()));
		output.append("\nError Rate of Classifier: " + evaluation.errorRate());
		output.append("\nConfusion Matrix of the Classifier: \n" + evaluation.toMatrixString("Case 6"));
		output.append("\nWeighted Precision of Classifier: " + evaluation.weightedPrecision());
		output.append("\nWeighted Recall of Classifier: " + evaluation.weightedRecall());
		output.append("\n*******************************************************************\n");
		System.out.println(output.toString());
		
		//Case 7: Building the classifier with only Title and Description feature
		evaluation = nb.createInstanceTitleDescription(noOfFolds, noOfSeeds);
		
		output = new StringBuilder();
		output.append("\n*******************************************************************\n");
		output.append(
				"Case 7: Building the Naive Bayesian Classifier with  options for only Title and Description feature Output:");
		output.append("\nTotal Instance: " + evaluation.numInstances());
		output.append("\nPercentage of Correctly Classified Instance: " + evaluation.pctCorrect()+"%");
		output.append("\nPercentage of InCorrectly Classified Instance: " + evaluation.pctIncorrect() +"%");
		output.append("\nPercentage of UnClassified Instances: " + evaluation.pctUnclassified() +"%");
		output.append("\nAccuracy of Classifier: " + (evaluation.correct() / evaluation.numInstances()));
		output.append("\nError Rate of Classifier: " + evaluation.errorRate());
		output.append("\nConfusion Matrix of the Classifier: \n" + evaluation.toMatrixString("Case 7"));
		output.append("\nWeighted Precision of Classifier: " + evaluation.weightedPrecision());
		output.append("\nWeighted Recall of Classifier: " + evaluation.weightedRecall());
		output.append("\n*******************************************************************\n");
		System.out.println(output.toString());
	}

}
